package fsm

//有限状态机模型的元素由以下组成：
//状态（State）：事物的状态，包括初始状态和所有事件触发后的状态。
//事件（Event）：触发状态变化或者保持原状态的事件。
//行为或转换（Action/Transition）：执行状态转换的过程。
//检测器（Guard）：检测某种状态要转换成另一种状态的条件是否满足

type FSMEvent string

type IFSMState interface {
	// 进入状态
	Enter(args ...interface{}) error
	// 退出状态
	Leave(args ...interface{}) error
	// 状态转移检测
	CheckTransition(args ...interface{}) bool
}

//
type FSMState struct{}

// 进入状态
func (fsms *FSMState) Enter(args ...interface{}) error {
	return nil
}

// 退出状态
func (fsms *FSMState) Leave(args ...interface{}) error {
	return nil
}

// 状态转移检测
func (fsms *FSMState) CheckTransition(args ...interface{}) bool {
	return true
}

//状态机进行状态迁移的条件:由前一个状态和触发事件共同唯一确定
type stateTransitionKey struct {
	SrcState IFSMState //源状态
	Event    FSMEvent  //触发迁移的事件
}

//状态迁移描述
type StateTransitionDesc struct {
	SrcState IFSMState //源状态
	Event    FSMEvent  //触发迁移的事件
	DstState IFSMState //目的状态
}

//FSM 持有有限多个状态集合，有当前状态、默认状态、接收的外部数据等。并且 FSM 有一系列的行为：启动 FSM、退出 FSM 以及状态转移等。
//State（状态）也会有一系列的行为：进入状态，转移状态等。并且 State 还有动作行为，比如电视机当前频道正在播放西游记，切换频道后就变成了播放封神榜，原理上是一样的.

type FSM struct {
	// 迁移图：迁移触发的条件，前一个状态+触发事件  ---> 目的状态
	transitions map[stateTransitionKey]IFSMState
	// 当前状态
	currentState IFSMState
	// 默认状态
	defaultState IFSMState
}

func NewFSM() *FSM {
	return &FSM{}
}

// 初始化FSM
func (fsm *FSM) Init(current IFSMState) {
	fsm.currentState = current
}

// 添加状态迁移关系到FSM
func (fsm *FSM) AddStateTransitions(std []StateTransitionDesc) {
	if fsm.transitions == nil {
		fsm.transitions = make(map[stateTransitionKey]IFSMState, len(std))
	}
	for _, desc := range std {
		fsm.transitions[stateTransitionKey{SrcState: desc.SrcState, Event: desc.Event}] = desc.DstState
	}
}

func (fsm *FSM) AddEventTransitions(event FSMEvent, srcs []IFSMState, dst IFSMState) {
	if fsm.transitions == nil {
		fsm.transitions = make(map[stateTransitionKey]IFSMState, len(srcs))
	}
	for _, src := range srcs {
		fsm.transitions[stateTransitionKey{SrcState: src, Event: event}] = dst
	}
}

// 设置默认的State
func (fsm *FSM) SetDefaultState(state IFSMState) {
	fsm.defaultState = state
}

func (fsm *FSM) CurrentState() IFSMState {
	return fsm.currentState
}

// 转移状态
func (fsm *FSM) doTransitionState(event FSMEvent, args ...interface{}) error {
	key := stateTransitionKey{SrcState: fsm.currentState, Event: event}
	if nextState, exist := fsm.transitions[key]; exist {
		if ok := nextState.CheckTransition(args); ok {
			if fsm.currentState != nil {
				// 退出前一个状态
				fsm.currentState.Leave(args)
			}
			fsm.currentState = nextState
			nextState.Enter(args)
		}
	}
	return nil
}

// 事件触发状态迁移
func (this *FSM) Event(event FSMEvent, args ...interface{}) error {
	return this.doTransitionState(event, args)
}
